﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;

namespace Apewer.Network
{

    /// <summary>HTTP 头的集合。</summary>
    [Serializable]
    public sealed class HttpHeaders : IEnumerable<HttpHeader>, ICollection<HttpHeader>, IToJson
    {

        #region IEnumerable

        List<HttpHeader> _list = new List<HttpHeader>();
        long _version = 0L;

        /// <summary>获取枚举器。</summary>
        public IEnumerator<HttpHeader> GetEnumerator() => new Enumerator(this);

        /// <summary>获取枚举器。</summary>
        IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this);

        /// <summary></summary>
        public sealed class Enumerator : IEnumerator<HttpHeader>
        {

            HttpHeaders _headeres = null;
            long _version = 0L;
            bool _disposed = false;

            HttpHeader _current = null;
            int _index = 0;

            const string ObjectName = nameof(Enumerator);
            const string OriginChanged = "原集合已变更，无法继续遍历。";

            /// <summary></summary>
            public HttpHeader Current
            {
                get
                {
                    if (_disposed) throw new ObjectDisposedException(ObjectName);
                    if (_version != _headeres._version) throw new InvalidOperationException(OriginChanged);
                    return _current;
                }
            }

            /// <summary></summary>
            object IEnumerator.Current { get => Current; }

            /// <summary></summary>
            public void Dispose() { _disposed = true; }

            /// <summary></summary>
            public bool MoveNext()
            {
                if (_disposed) throw new ObjectDisposedException(ObjectName);
                if (_version != _headeres._version) throw new InvalidOperationException(OriginChanged);

                if (_index < _headeres._list.Count)
                {
                    _current = _headeres._list[_index];
                    _index++;
                    return true;
                }

                return false;
            }

            /// <summary></summary>
            public void Reset()
            {
                _current = null;
                _index = 0;
            }

            /// <exception cref="ArgumentNullException" />
            public Enumerator(HttpHeaders headers)
            {
                if (headers == null) throw new ArgumentNullException(nameof(headers));
                _headeres = headers;
                _version = headers._version;
                Reset();
            }

        }

        #endregion

        #region ICollection

        /// <summary>元素数量。</summary>
        public int Count { get => _list.Count; }

        /// <summary>当前集合是只读。</summary>
        public bool IsReadOnly { get => false; }

        /// <summary>添加一项。</summary>
        /// <exception cref="ArgumentNullException" />
        public HttpHeader Add(string name, string value)
        {
            if (name.IsEmpty()) throw new ArgumentNullException(nameof(name));
            var header = new HttpHeader(name, value);
            _list.Add(header);
            _version++;
            return header;
        }

        /// <summary>添加一项。</summary>
        /// <exception cref="ArgumentNullException" />
        public void Add(HttpHeader header)
        {
            if (header == null) throw new ArgumentNullException(nameof(header));
            _list.Add(header);
            _version++;
        }

        /// <summary>移除所有元素。</summary>
        public void Clear() => _list.Clear();

        /// <summary>判断是否包含指定的元素。</summary>
        public bool Contains(HttpHeader item) => _list.Contains(item);

        /// <summary>复制所有元素到数组。</summary>
        /// <param name="array">目标数组。</param>
        /// <param name="arrayIndex">数组的位置。</param>
        /// <exception cref="ArgumentNullException" />
        /// <exception cref="ArgumentOutOfRangeException" />
        /// <exception cref="ArgumentException" />
        public void CopyTo(HttpHeader[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);

        /// <summary>移除指定的元素</summary>
        public bool Remove(HttpHeader item) => _list.Remove(item);

        #endregion

        #region IList

        /// <summary></summary>
        /// <exception cref="ArgumentOutOfRangeException" />
        public HttpHeader this[int index] { get => _list[index]; set => _list[index] = value; }

        /// <summary></summary>
        /// <exception cref="ArgumentOutOfRangeException" />
        public string this[string name] { get => GetValue(name); set => SetValue(name, value); }

        /// <summary>搜索指定对象在当前集合中的位置索引。</summary>
        public int IndexOf(HttpHeader item) => _list.IndexOf(item);

        /// <summary>插入元素到指定位置。</summary>
        /// <exception cref="ArgumentOutOfRangeException" />
        public void Insert(int index, HttpHeader item) => _list.Insert(index, item);

        /// <summary>移除指定位置的元素。</summary>
        /// <exception cref="ArgumentOutOfRangeException" />
        public void RemoveAt(int index) => _list.RemoveAt(index);

        #endregion

        #region constructor

        /// <summary></summary>
        public HttpHeaders() { }

        /// <summary></summary>
        /// <exception cref="ArgumentNullException" />
        public HttpHeaders(params HttpHeader[] headers) : this(headers as IEnumerable<HttpHeader>) { }

        /// <summary></summary>
        /// <exception cref="ArgumentNullException" />
        public HttpHeaders(IEnumerable<HttpHeader> headers)
        {
            if (headers == null) throw new ArgumentNullException(nameof(headers));

            foreach (var header in headers)
            {
                if (header == null) continue;
                if (header.Name.IsEmpty()) continue;
                Add(header);
            }
        }

        /// <summary></summary>
        /// <exception cref="ArgumentNullException" />
        public HttpHeaders(IEnumerable<KeyValuePair<string, string>> headers)
        {
            if (headers == null) return;

            foreach (var header in headers)
            {
                if (header.Key.IsEmpty()) continue;
                Add(header.Key, header.Value);
            }
        }

        /// <summary></summary>
        /// <exception cref="ArgumentNullException" />
        public HttpHeaders(NameValueCollection headers)
        {
            if (headers == null) return;

            var keys = headers.AllKeys;
            foreach (var key in keys)
            {
                if (key.IsEmpty()) continue;
                var value = headers[key];
                Add(key, value);
            }
        }

        #endregion

        #region operation

        /// <summary>获取所有名称。</summary>
        public string[] GetNames()
        {
            var names = new List<string>();
            var count = _list.Count;
            for (var i = 0; i < count; i++)
            {
                var name = _list[i].Name;
                if (string.IsNullOrEmpty(name)) continue;
                if (names.Contains(name)) continue;
                names.Add(name);
            }
            names.Sort();
            return names.ToArray();
        }

        /// <summary>获取匹配 Name 的 Value。不存在 Name 时返回 NULL 值。</summary>
        /// <exception cref="ArgumentNullException" />
        public string GetValue(string name)
        {
            if (name.IsEmpty()) throw new ArgumentNullException(nameof(name));

            // 精准匹配。
            var count = _list.Count;
            for (var i = 0; i < count; i++)
            {
                var item = _list[i];
                if (string.IsNullOrEmpty(item.Name)) continue;
                if (item.Name == name)
                {
                    if (string.IsNullOrEmpty(item.Value)) continue;
                    return item.Value;
                }
            }

            // 忽略大小写。
            var lower = TextUtility.Lower(name);
            for (var i = 0; i < count; i++)
            {
                var item = _list[i];
                if (string.IsNullOrEmpty(item.Name)) continue;
                if (TextUtility.Lower(item.Name) == lower)
                {
                    if (string.IsNullOrEmpty(item.Value)) continue;
                    return item.Value;
                }
            }

            return null;
        }

        /// <summary>获取匹配 Name 的 Value。不存在 Name 时返回 NULL 值。</summary>
        /// <exception cref="ArgumentNullException" />
        public string[] GetValues(string name)
        {
            if (name.IsEmpty()) throw new ArgumentNullException(nameof(name));

            // 忽略大小写。
            // name = TextUtility.Lower(name);

            var count = _list.Count;
            var values = new List<string>(_list.Count);
            for (var i = 0; i < count; i++)
            {
                var item = _list[i];
                if (string.IsNullOrEmpty(item.Name)) continue;
                if (string.Equals(item.Name, name, StringComparison.CurrentCultureIgnoreCase))
                {
                    var value = item.Value.ToTrim();
                    if (string.IsNullOrEmpty(value)) continue;
                    values.Add(value);
                }
            }

            return values.ToArray();
        }

        /// <summary>设置 Name 的 Value。不存在 Name 时添加新元素。</summary>
        /// <exception cref="ArgumentNullException" />
        public HttpHeader SetValue(string name, string value)
        {
            if (name.IsEmpty()) throw new ArgumentNullException(nameof(name));

            // 尝试精准匹配。
            var count = _list.Count;
            for (var i = 0; i < count; i++)
            {
                var item = _list[i];
                if (string.IsNullOrEmpty(item.Name)) continue;
                if (item.Name == name)
                {
                    item.Value = value;
                    _version++;
                    return item;
                }
            }

            // 尝试模糊匹配。
            var lower = TextUtility.Lower(name);
            for (var i = 0; i < count; i++)
            {
                var item = _list[i];
                if (TextUtility.Lower(item.Name) == lower)
                {
                    item.Value = value;
                    _version++;
                    return item;
                }
            }

            // 添加新项。
            return Add(name, value);
        }

        /// <summary>按名称排序。</summary>
        public void Sort() => _list.Sort();

        /// <summary>按指定的方式排序。</summary>
        public void Sort(IComparer<HttpHeader> comparer) => _list.Sort(comparer ?? throw new ArgumentNullException(nameof(comparer)));

        /// <summary>按指定的方式排序。</summary>
        public void Sort(Comparison<HttpHeader> comparison) => _list.Sort(comparison ?? throw new ArgumentNullException(nameof(comparison)));

        /// <summary>每个元素组成为新数组。</summary>
        public HttpHeader[] ToArray() => _list.ToArray();

        /// <summary>生成 <see cref="StringPairs"/> 数组。</summary>
        public StringPairs ToStringParis()
        {
            var sp = new StringPairs();
            foreach (var item in _list) sp.Add(item.Name, item.Value);
            return sp;
        }

        /// <summary></summary>
        public override string ToString() => $"Count = {_list.Count}";

        /// <summary></summary>
        public static implicit operator StringPairs(HttpHeaders headers) => headers?.ToStringParis();

        #endregion

        #region Json

        internal HttpHeaders(Json json)
        {
            if (!json) return;

            if (json.IsObject)
            {
                var properties = json.GetProperties();
                foreach (var property in properties)
                {
                    if (property == null) continue;
                    if (property.Name.IsEmpty()) continue;
                    Add(property.Name, property.Value?.ToString());
                }
            }

            if (json.IsArray)
            {
                var array = json.Array<HttpHeader>();
                if (array != null)
                {
                    for (var i = 0; i < array.Length; i++)
                    {
                        if (array[i] == null) continue;
                        if (array[i].Name.IsEmpty()) continue;
                        _list.Add(array[i]);
                    }
                }
            }
        }

        /// <summary></summary>
        public Json ToJson()
        {
            var array = Json.NewArray();
            var count = 0;
            for (var i = 0; i < count; i++)
            {
                var item = Json.From(_list[i]);
                array.AddItem(item);
            }
            return array;
        }

        #endregion

    }

}
